package cn.edu.jxust.core.domain.repository.impl;

import cn.edu.jxust.core.infrastructure.OneNetConst;
import cn.edu.jxust.common.domain.entity.Aqi;
import cn.edu.jxust.common.domain.valobj.AirVo;
import cn.edu.jxust.common.domain.valobj.AirVoSimple;
import cn.edu.jxust.common.domain.valobj.AqiVo;
import cn.edu.jxust.common.domain.valobj.DayPollutionAirs;
import cn.edu.jxust.common.domain.dto.MainPollutionDayVo;
import cn.edu.jxust.core.infrastructure.mapper.AqiMapper;
import cn.edu.jxust.core.infrastructure.mapper.DeviceMapper;
import cn.edu.jxust.common.response.Result;
import cn.edu.jxust.common.response.ResultUtils;
import cn.edu.jxust.common.response.enums.ResultStatus;
import cn.edu.jxust.core.domain.repository.AqiService;
import cn.edu.jxust.core.infrastructure.util.AqiUtils;
import cn.edu.jxust.core.infrastructure.util.Const;
import cn.edu.jxust.core.infrastructure.util.DateUtils;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.DoubleSummaryStatistics;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * @author QiuKangming
 * @since 2020-06-29
 */
@Service
public class AqiServiceImpl extends ServiceImpl<AqiMapper, Aqi> implements AqiService {

    @Resource
    private AqiMapper aqiMapper;
    @Resource
    private DeviceMapper deviceMapper;

    /**
     * 获取指定日期的Aqi列表
     * @param deviceId 设备id号
     * @param beginTime 开始时间
     * @param endTime 结束时间
     * @param aqiType aqi类型
     * @return List<AqiVo>
     */
    @Override
    public Result getAqiList(Integer deviceId, String beginTime, String endTime, String aqiType) {

        //检查设备是否正常,即是否绑定监测点
        if(checkDeviceIsNotBinding(deviceId)){
            //设备未绑定
            return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "暂无设备信息输入, 请检查您的设备是否有绑定监测点?");
        }

        QueryWrapper<Aqi> wrapper = new QueryWrapper<>();
        wrapper.isNull("airtype_id")
                .eq("device_id", deviceId)
                .eq("aqi_type", aqiType)
                .between("create_datetime", beginTime, endTime)
                .orderByAsc("create_datetime");
        List<Aqi> aqiList = aqiMapper.selectList(wrapper);
        List<AqiVo> aqiVoList = this.toAqiVo(aqiList);
        if(!aqiVoList.isEmpty()){
            return ResultUtils.resultWithData(ResultStatus.SUCCESS, aqiVoList);
        }else{
            return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "未找到该时间段内任何 aqi 数据");
        }

    }

    /**
     * 获取昨天的每种气体小时的 Aqi 对象值, 带 iAqi
     * @param deviceId 设备id
     * @param begin 开始时间
     * @param end 结束时间
     * @return List<Aqi>
     */
    @Override
    public List<Aqi> getLastDayiAqiList(Integer deviceId, String begin, String end) {

        QueryWrapper<Aqi> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("airtype_id")
                .eq("aqi_type", AqiUtils.HAQI)
                .eq("device_id", deviceId)
                .between("create_datetime", begin, end);
        return aqiMapper.selectList(wrapper);

    }

    /**
     * 获取大气污染物分担率
     * @param deviceId 设备id号
     * @param beginDate 开始日期
     * @param endDate 结束日期
     * @return List<AirVo>
     */
    @Override
    public Result getPollutionShareRate(Integer deviceId, String beginDate, String endDate) {

        //检查设备是否正常,即是否绑定监测点
        if(checkDeviceIsNotBinding(deviceId)){
            //设备未绑定
            return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "暂无设备信息输入, 请检查您的设备是否有绑定监测点?");
        }

        //如果查询结束的时间是今天的话, 默认把endDate的值改为当前时间
        long currentTimeMillis = System.currentTimeMillis();
        if (endDate.equals(DateUtils.getTodayDate(currentTimeMillis))) {
            endDate = DateUtils.getTodayDateTime(currentTimeMillis);
        }

        //检查前端传过来的日期是否正确
        if(DateUtils.getDays(beginDate, endDate) <= 0){
            return ResultUtils.resultWithoutData(ResultStatus.FAILED, "所选日期不符合规定");
        }

        //查询出该段时间内的数据
        List<AirVo> list = aqiMapper.getPollutionShareRate(deviceId, AqiUtils.DAQI, beginDate, endDate);
        //查询出该段时间内的所有气体的日均平均溶度: 用于做饼图的数据
        Map<String, DoubleSummaryStatistics> map = list.stream()
                .collect(Collectors.groupingBy(AirVo::getAirName, Collectors.summarizingDouble(AirVo::getConcentration)));
        List<AirVoSimple> airVoSimpleList = new ArrayList<>(map.size());
        map.forEach((k, v) -> airVoSimpleList.add(AirVoSimple.builder().airName(k).concentration(v.getAverage()).build()));
        //计算实际查询出来的日期集合
        List<String> dateList = list.stream().map(AirVo::getDate).distinct().collect(Collectors.toList());
        List<DayPollutionAirs> dayPollutionAirsList = new ArrayList<>(dateList.size());
        dateList.forEach(date -> dayPollutionAirsList.add(DayPollutionAirs.builder().date(date).build()));

        dayPollutionAirsList.forEach(day -> list.forEach(airVo -> {
            if(day.getDate().equals(airVo.getDate())){
                switch (airVo.getAirName()) {
                    case OneNetConst.PM25:
                        day.setPM25(airVo.getConcentration());
                        break;
                    case OneNetConst.PM10:
                        day.setPM10(airVo.getConcentration());
                        break;
                    case OneNetConst.SO2:
                        day.setSO2(airVo.getConcentration());
                        break;
                    case OneNetConst.NO2:
                        day.setNO2(airVo.getConcentration());
                        break;
                    case OneNetConst.O3:
                        day.setO3(airVo.getConcentration());
                        break;
                    case OneNetConst.CO:
                        day.setCO(airVo.getConcentration());
                        break;
                }
            }
        }));

        if(airVoSimpleList.size() != 0 && dayPollutionAirsList.size() != 0){
            Map<String, Object> result = new HashMap<>(2);
            result.put("draw", airVoSimpleList);
            result.put("table", dayPollutionAirsList);
            return ResultUtils.resultWithData(ResultStatus.SUCCESS, result);
        }
        return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "未找到该时间段内的任何信息");

    }

    /**
     * 获取大气单项污染指数
     * @param deviceId 设备id号
     * @param airType 气体类型
     * @param beginDate 开始日期
     * @param endDate 结束日期
     * @return IPage<AqiVo>
     */
    @Override
    public Result getOneAirList(Integer deviceId, Integer airType, String beginDate, String endDate) {

        //检查设备是否正常,即是否绑定监测点
        if(checkDeviceIsNotBinding(deviceId)){
            //设备未绑定
            return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "暂无设备信息输入, 请检查您的设备是否有绑定监测点?");
        }

        //如果查询结束的时间是今天的话, 默认把endDate的值改为当前时间
        long currentTimeMillis = System.currentTimeMillis();
        if (endDate.equals(DateUtils.getTodayDate(currentTimeMillis))) {
            endDate = DateUtils.getTodayDateTime(currentTimeMillis);
        }
        QueryWrapper<Aqi> wrapper = new QueryWrapper<>();

        //查询气体单项气体的Iaqi
        wrapper.eq("device_id", deviceId)
                .eq("airtype_id", airType)
                .eq("aqi_type", AqiUtils.DAQI)
                .between("create_datetime", beginDate, endDate);
        List<AqiVo> aqiVoList = this.toAqiVo(aqiMapper.selectList(wrapper));
        if(!aqiVoList.isEmpty()){
            return ResultUtils.resultWithData(ResultStatus.SUCCESS, aqiVoList);
        }else{
            return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "未找到任何该段时间内该污染物数据");
        }

    }

    /**
     * 获取首要污染物天数构成
     * @param deviceId 设备id号
     * @param beginDate 开始日期
     * @param endDate 结束日期
     * @return List<MainPollutionDayVo>
     */
    @Override
    public Result getMainPollutionDay(Integer deviceId, String beginDate, String endDate) {

        //检查设备是否正常,即是否绑定监测点
        if(checkDeviceIsNotBinding(deviceId)){
            //设备未绑定
            return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "暂无设备信息输入, 请检查您的设备是否有绑定监测点?");
        }

        //根据查询的时间段:
        //1. 计算出这个查询时间段内的天数
        long days = DateUtils.getDays(beginDate, endDate);
        if(days <= 0){
            return ResultUtils.resultWithoutData(ResultStatus.FAILED, "所选日期不符合规定");
        }
        beginDate = beginDate + " 00:00:00";
        endDate = endDate + " 23:59:59";
        List<MainPollutionDayVo> list = aqiMapper.getMainPollutionDayVoList(deviceId, AqiUtils.DAQI, beginDate, endDate);
        if(null == list || list.size() == 0){
            return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "未找到该时间段内任何污染物信息");
        }
        list.forEach( li -> {
            if(li.getMainPollution().equals("--")){
                li.setMainPollution("无首要污染物");
            }
            li.setPercent(li.getTotalDays() / (double) days);
        } );

        return ResultUtils.resultWithData(ResultStatus.SUCCESS, list);

    }

    /**
     * 获取前一天上传数据的设备ids
     * @param begin 开始日期时间
     * @param end 结束日期时间
     * @return List<Integer>
     */
    @Override
    public List<Integer> getLastDayDeviceIds(String begin, String end) {

        return aqiMapper.getLastDayDeviceIds(begin, end);

    }

    /**
     * 将List<Aqi>转换成 List<AqiVo>
     * @param aqis aqi 列表
     * @return List<AqiVo>
     */
    private List<AqiVo> toAqiVo(List<Aqi> aqis){

        //声明变量
        List<AqiVo> aqiVoList = new ArrayList<>(aqis.size());
        //遍历设备列表
        aqis.forEach(aqi -> {
            //1. 首先把相同的字段填充
            AqiVo aqiVo = new AqiVo();
            BeanUtil.copyProperties(aqi, aqiVo, "createDatetime");
            //判断aqi类型, 如果是日类型: 时间格式调整为 yyyy-MM-dd
            if(aqi.getAqiType().equals(AqiUtils.DAQI)){
                aqiVo.setCreateDatetime(aqi.getCreateDatetime().toLocalDate().toString());
            }else if(aqi.getAqiType().equals(AqiUtils.HAQI)){
                aqiVo.setCreateDatetime(aqi.getCreateDatetime().toString().replace('T', ' '));
            }
            aqiVo.setAqiLevelStr(AqiUtils.getAqiLevelStr(aqi.getAqiLevel()));
            aqiVoList.add(aqiVo);
        });

        return aqiVoList;

    }

    /**
     * 检查设备是否未绑定
     * @param deviceId 设备id
     * @return boolean ,true, 未绑定. false 绑定了
     */
    private boolean checkDeviceIsNotBinding(Integer deviceId){

        //检查设备是否正常,即是否绑定监测点
        int flg = deviceMapper.deviceIsBinding(deviceId);
        return Const.NOT_BINDING.equals(flg);

    }
}
